﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Policy;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.UI.HtmlControls;

namespace GPDWin4GameBarPowerBackend
{
    public partial class Service1 : ServiceBase
    {
        HttpListener listener;

        CancellationTokenSource stopSignal;

        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            Console.WriteLine("Started! ");

            var defaultGpu = Properties.Settings.Default.gpu;
            var defaultTdp = Properties.Settings.Default.tdp;

            TDPSet.TDPSet.SetGPUClock(defaultGpu);
            TDPSet.TDPSet.SetTDP(defaultTdp);

            Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            if (!Directory.Exists("htdocs"))
            {
                Directory.CreateDirectory("htdocs");
            }
            listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:26214/");
            listener.Start();
            stopSignal = new CancellationTokenSource();
            new Thread(ServerThread).Start();
        }

        private void ServerThread()
        {
            var cancellationToken = stopSignal.Token;
            try
            {
                while (true)
                {
                    var asyncGetContext = listener.GetContextAsync();

                    asyncGetContext.Wait(cancellationToken);
                    if (stopSignal.IsCancellationRequested)
                    {
                        throw new OperationCanceledException();
                    }
                    var context = asyncGetContext.Result;
                    if (context != null)
                    {
                        Task.Run(() =>
                        {
                            var currentContext = context;
                            ProcessRequest(currentContext);
                        });
                    }
                }
            }
            catch (OperationCanceledException)
            {
                listener.Prefixes.Clear();
                listener.Stop();
                listener = null;
            }
          
        }

        private void ProcessRequest(HttpListenerContext context)
        {
            var uri = context.Request.Url.AbsolutePath;
            if (uri.StartsWith("/api"))
            {
                ProcessAPI(context);
                return;
            }
            ProcessStaticResource(context);
        }

        private void ProcessAPI(HttpListenerContext context)
        {
            var localPath = context.Request.Url.AbsolutePath;
            if (!localPath.StartsWith("/")) { localPath = "/" + localPath; }
            if (localPath == "/api/tdp")
            {
                var query = context.Request.QueryString;
                var tdpstr = query["tdp"];
                var gpustr = query["gpu"];
                try
                {
                    if (int.TryParse(gpustr, out var gpu))
                    {
                        TDPSet.TDPSet.SetGPUClock(gpu);
                        Properties.Settings.Default.gpu = gpu;
                    }
                    if (int.TryParse(tdpstr, out var tdp))
                    {
                        TDPSet.TDPSet.SetTDP(tdp); 
                        Properties.Settings.Default.tdp = tdp;
                    }
                    Properties.Settings.Default.Save();
                    SendApiResult(context, 200, "Success");
                }catch(Exception ex)
                {
                    SendApiResult(context, 500, ex.Message);
                }
                return;
            }
            if (localPath == "/api/altf4")
            {
                new Thread(() =>
                {
                    ProcessAsUser.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AltF4Sender.exe"),true);

                }).Start();
                SendApiResult(context, 200, "Success");
                return;
            }
            context.Response.StatusCode = 404;
            context.Response.Close();
        }

        JavaScriptSerializer JSON = new JavaScriptSerializer();

        private void SendApiResult(HttpListenerContext context, int code, string msg, object data = null)
        {
            string json = JSON.Serialize(new { 
                code,
                msg,
                data
            });
            context.Response.StatusCode = 200;
            context.Response.SendChunked = true;
            context.Response.ContentType  = "application/json";
            using(StreamWriter sw = new StreamWriter(context.Response.OutputStream))
            {
                sw.Write(json);
                sw.Flush();
            }
            context.Response.Close();
        }

        private void ProcessStaticResource(HttpListenerContext context)
        {
            var localPath = context.Request.Url.AbsolutePath;
            if (!localPath.StartsWith("/")) { localPath = "/" + localPath; }
            localPath = "htdocs" + localPath;
            if (localPath.EndsWith("/")) { localPath += "index.html"; }
            if (!File.Exists(localPath) && Directory.Exists(localPath))
            {
                localPath += "/index.html";
            }
            if (File.Exists(localPath))
            {
                string mimetype = MimeMapping.GetMimeMapping(localPath);
                long contentLength = new FileInfo(localPath).Length;

                if (mimetype == null) { mimetype = "application/octet-stream"; }
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.ContentLength64 = contentLength;
                context.Response.ContentType = mimetype;
                context.Response.ContentEncoding = Encoding.UTF8;
                using (FileStream fs = File.OpenRead(localPath))
                {
                    fs.CopyTo(context.Response.OutputStream);
                }
                context.Response.Close();
            }
        }

        protected override void OnStop()
        {
            stopSignal?.Cancel();
        }
    }
}
